#include <iostream>
using namespace std;

//多态：不同类型的对象去做同一个行为，结果不同

// 虚函数
class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
	
	//第一个条件不满足，结果都是全价，不是多态
	//void BuyTicket() { cout << "买票-全价" << endl; } 
};

//虚函数的重写/覆盖
class Student : public Person {
public:
	//子类都不写的的时候，也全调用父类
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
	
	/*注意：在重写基类虚函数时，派生类的虚函数在不加virtual关键字时，虽然也可以构成重写(因
	为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范，不建议
	这样使用*/
	
	//派生类不加virtual，也是多态
	//void BuyTicket() { cout << "买票-半价" << endl; }
};

//多态不仅发生在父子类之间，还可以发生在多个子类间
class Soldier :public Person {
public:
	virtual void BuyTicket() { cout << "买票-优先" << endl; }
	
	//void BuyTicket() { cout << "买票-优先" << endl; }
};



//多态的要求
// 1、虚函数重写：其要求三同（函数名，参数，返回）
// 2、父类指针或者引用调用虚函数


void Func(Person& p) { 
	p.BuyTicket();

	//指定域去访问也不是多态
	//p.Person::BuyTicket();
}

//注意：父类不能调用子类形成多态
//void Func3(Student& s){  s.BuyTicket(); }

void Func1(Person p) { //不符合第二个条件,此时不属于多态
	p.BuyTicket();
}

void Func2(Person* p){ 
	p->BuyTicket();

	//指定域去访问也不是多态
	//p->Person::BuyTicket();
}

void Func3(Person p){
	Person* ptr = &p;
	ptr->BuyTicket(); //虽然下面指针符合多态，但是ptr指向的都是父类对象，没有做到指向父类和子类
}


int main(){

	Person p;
	Student s;

	//多态行为，不同的人做产生结果不同
	cout << "父类指针\n";
	Func(p);
	Func(s);

	cout << "\n不调用父类指针\n";
	Func1(p);
	Func1(s);

	cout << "\n引用调用虚函数\n";
	Func2(&p);
	Func2(&s);

	cout << "\n多态可以发生在子类中\n";
	Soldier so;
	Func(so);
	Func1(so);
	Func2(&so);

	cout << "\n不符合多态就是隐藏\n";
	//不构成多态就是隐藏,重写属于一种特殊的隐藏，不仅要求函数名相同，还有上面两个要求
	s.BuyTicket();
	s.Person::BuyTicket();

	cout << "\nFunc(3)\n";
	Func3(p);
	Func3(s);
	Func3(so);


	return 0;
}